import React, {
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import {
  UPDATE_ERRORS,
  UPDATE_ISCANEDIT,
  UPDATE_NAME,
} from '../../context/table';
import { ActionColumn as Action, DisplayTable, TableModal } from '../index';
import TableContext from '../TableContext';
import { EditableTableCell, TablePopModal } from './index';

import { prefix } from '../../../config';
import { deepClone } from '../../../utils';
import {
  EDITABLE_TABLE,
  TABLE_ACTION_CELL,
  defaultColumnConfig,
  defaultPagination,
  defaultRowKey,
} from '../../config';
import * as utils from '../../utils';

import type { Context } from '../../context/table';
import type {
  AnyObject,
  Column,
  EditableTableProps,
  TableContextRef,
  TableSelectType,
} from '../../type';
import type { Props as TableModalProps } from '../TableModal';
import type { Props as TablePopModalProps } from './TablePopModal';

const getDefaultTableModal = (
  isCanRepeatSelection: boolean,
  selectType: TableSelectType,
) => ({
  columns: [],
  dataSource: [],
  pagination: { ...defaultPagination },
  rowSelection: {
    isCanRepeatSelection,
    type: selectType,
    selectedRows: [],
  },
});
function EditableTable<T extends AnyObject>(
  props: EditableTableProps<T>,
  ref: React.ForwardedRef<TableContextRef<T>>,
) {
  const {
    modal = {},
    action,
    rowKey = defaultRowKey,
    context,
    columns = [],
    dataSource = [],
    pagination,
    filterCopyKey,
    defaultRows = 2,
    isSaveInRealTime = true,
    prefixCls = prefix.editableTable,
    ...restProps
  } = props;
  const {
    isUsePop = true,
    modalDataDetailKey = 'modalDataDetail',
    ...tableModal
  } = modal;
  const {
    selectType = 'checkbox',
    isCanRepeatSelection = true,
    rowKey: modalRowKey = defaultRowKey,
  } = tableModal;
  const {
    table: tableContextInfo,
    table: { curOperateInfo }, // 当前操作的表格信息
    dispatch,
  } = useContext<Context<T>>(context);
  const displayTableRef = useRef<TableContextRef<T>>(null);
  // 弹窗选择
  const [selectTableModal, setSelectTableModal] = useState<TableModalProps<T>>({
    ...tableModal,
    ...getDefaultTableModal(isCanRepeatSelection, selectType),
    rowKey: modalRowKey,
    curOperateInfo,
    visible: false,
  });
  // 单元格搜索选择
  const [selectPopModalProps, setSelectPopModalProps] = useState<
    TablePopModalProps<T>
  >({
    ...tableModal,
    ...getDefaultTableModal(isCanRepeatSelection, selectType),
    rowKey: modalRowKey,
    context,
    visible: false,
  });

  const tableData = useMemo(() => {
    const initDataSource = utils.createInitTableData(
      dataSource,
      columns,
      defaultRows,
    );

    return utils.handleRowKey(initDataSource, pagination, rowKey); // 添加dataSource key字段
    // return initDataSource;
  }, [dataSource, defaultRows, columns]);
  const add = useCallback(
    utils.getAddHandler(columns, props.onChangeDataSource),
    [columns],
  );
  const update = useCallback(utils.getUpdateHandler(props.onChangeDataSource), [
    tableData,
  ]);
  const remove = useCallback(utils.getDeleteHandler(props.onChangeDataSource), [
    tableData,
  ]);

  const tableColumns: Column<T>[] = useMemo(() => {
    const tableColumns = deepClone(columns);
    // 表格操作
    !!tableColumns.length &&
      tableColumns.push({
        id: TABLE_ACTION_CELL,
        header: '操作',
        meta: { ...defaultColumnConfig[TABLE_ACTION_CELL] },
        cell: (info) => {
          const { row } = info;

          return (
            <Action
              action={action}
              onAdd={() => add(row.index, tableData)}
              onRemove={() => remove(row.index, tableData)}
              onCopy={() =>
                add(row.index, tableData, row.original, filterCopyKey)
              }
            />
          );
        },
      });
    return tableColumns;
  }, [columns, action, tableData, filterCopyKey]);
  // 编辑单元格设置
  const defaultColumn: Partial<Column<T>> = {
    cell: (info) => {
      const cellProps = {
        rowKey,
        pagination,
        info,
        tableColumns,
        context,
        selectPopModalProps,
        selectTableModal,
        isUsePop,
      };
      return (
        <EditableTableCell
          {...cellProps}
          dataSource={tableData}
          onCell={props.onCell}
          setSelectTableModal={setSelectTableModal}
          setSelectPopModalProps={setSelectPopModalProps}
        />
      );
    },
  };

  const getModalData = async (
    page: number,
    size: number,
    params?: AnyObject,
  ) => {
    const {
      meta: { getModalData },
    } = curOperateInfo;
    if (getModalData) {
      return getModalData(page, size, params);
    } else {
      return { page, size, total: 0, list: [] };
    }
  };
  const onConfirm = (state: AnyObject, setState: React.SetStateAction<any>) => {
    return async (selectedRows) => {
      const { rowIndex } = curOperateInfo;
      const initRowData = utils.createInitRowData(columns);
      const selectedRowsData = [
        ...selectedRows.map((row) => ({ ...initRowData, ...row })),
      ];
      if (tableModal.getModalDataDetail) {
        for (let row of selectedRowsData) {
          const res = await tableModal.getModalDataDetail(row);
          row[modalDataDetailKey] = res;
        }
      }
      const [firstRow, ...restRows] = selectedRowsData;
      const updatedDataSource =
        firstRow && update(rowIndex, firstRow, tableData);
      // const updatedTableData =
      restRows && restRows.length
        ? add(rowIndex, updatedDataSource as T[], restRows)
        : updatedDataSource;
      // 弹窗选择数据后重新校验表格
      // validateTable(updatedTableData);
      setState({
        ...state,
        ...getDefaultTableModal(isCanRepeatSelection, selectType),
        visible: false,
      });
      tableModal.onConfirm && tableModal.onConfirm(selectedRows);
    };
  };
  const onCancel = (state: AnyObject, setState: React.SetStateAction<any>) => {
    setState({
      ...state,
      ...getDefaultTableModal(isCanRepeatSelection, selectType),
      visible: false,
    });
    tableModal.onCancel && tableModal.onCancel();
  };
  const onSearch = async (params: AnyObject) => {
    const pagination = selectTableModal.pagination || defaultPagination;
    const { page, size, total, list } = await getModalData(
      1,
      pagination.pageSize,
      params,
    );
    setSelectTableModal({
      ...selectTableModal,
      dataSource: list,
      pagination: { current: page, pageSize: size, total },
    });
  };
  const onReset = async () => {
    const pagination = selectTableModal.pagination || defaultPagination;
    const { page, size, total, list } = await getModalData(
      1,
      pagination.pageSize,
    );
    setSelectTableModal({
      ...selectTableModal,
      dataSource: list,
      pagination: { current: page, pageSize: size, total },
    });
  };
  const onChangePagination = (
    state: AnyObject,
    setState: React.SetStateAction<any>,
    isScrollRequst = false,
  ) => {
    return async (current: number, pageSize: number, params?: AnyObject) => {
      const { page, size, total, list } = await getModalData(
        current,
        pageSize,
        params,
      );
      setState({
        ...state,
        dataSource: !isScrollRequst ? list : [...state.dataSource, ...list],
        pagination: { current: page, pageSize: size, total },
      });
    };
  };

  const tableMeta = {
    updateCellData: (rowIndex, columnId, value) => {
      const dataSource = tableData.map((row, index) =>
        index === rowIndex
          ? { ...tableData[rowIndex]!, [columnId]: value }
          : row,
      );
      props.onChangeDataSource(dataSource);
    },
  };
  const tableOptions = { defaultColumn, meta: tableMeta };
  const displayTableProps = {
    ...restProps,
    rowKey,
    dataSource: tableData,
    columns: tableColumns,
    pagination,
  };
  // 校验整个表格
  const validateTable = (dataSource?: any[]) => {
    const errors = utils.validateTable(tableColumns, dataSource || tableData);
    dispatch({ type: UPDATE_ERRORS, payload: errors });
    return errors;
  };
  React.useImperativeHandle(ref, () => ({
    getTableContext: displayTableRef.current.getTableContext,
    onResizeTable: displayTableRef.current.onResizeTable,
    validateTable,
  }));
  useEffect(() => {
    if (!tableContextInfo.name)
      dispatch({ type: UPDATE_NAME, payload: EDITABLE_TABLE });
  }, [tableContextInfo.name]);
  useEffect(() => dispatch({ type: UPDATE_ISCANEDIT, payload: true }), []);

  return (
    <div className={`${prefixCls}-container`}>
      <DisplayTable
        {...displayTableProps}
        ref={displayTableRef}
        tableOptions={tableOptions}
        context={context}
      />
      <TableModal
        {...selectTableModal}
        onConfirm={(selectedRows) =>
          onConfirm(selectTableModal, setSelectTableModal)(selectedRows)
        }
        onCancel={() => onCancel(selectTableModal, setSelectTableModal)}
        onSearch={onSearch}
        onReset={onReset}
        onChangePagination={(page, pageSize, params) =>
          onChangePagination(selectTableModal, setSelectTableModal)(
            page,
            pageSize,
            params,
          )
        }
      />
      {isUsePop && (
        <TablePopModal
          {...selectPopModalProps}
          onConfirm={(selectedRows) =>
            onConfirm(selectPopModalProps, setSelectPopModalProps)(selectedRows)
          }
          onCancel={() => onCancel(selectPopModalProps, setSelectPopModalProps)}
          onChangePagination={(page, pageSize, params) =>
            onChangePagination(
              selectPopModalProps,
              setSelectPopModalProps,
              true,
            )(page, pageSize, params)
          }
        />
      )}
    </div>
  );
}

function EditableTableTableContext<T extends AnyObject>(
  props: EditableTableProps<T>,
  ref: React.ForwardedRef<TableContextRef<T>>,
) {
  return <TableContext {...props} Table={EditableTable} ref={ref} />;
}
export default React.forwardRef(EditableTableTableContext) as <T>(
  props: EditableTableProps<T> & {
    ref?: React.ForwardedRef<TableContextRef<T>>;
  },
) => ReturnType<typeof EditableTableTableContext>;
